package org.klarton.audio;

import org.klarton.filter.FilterBank;

import javax.sound.sampled.*;

/**
 * This class provides capturing. It will open an audio line and continuously pass
 * the read value from the line into the filters of the given filter bank.
 */
public class Capture extends Thread {

    private final FilterBank bank;
    private final TargetDataLine line;

    public Capture(FilterBank bank, final int sampleRate) throws LineUnavailableException {
        this.bank = bank;
        final AudioFormat format = getAudioFormat(sampleRate);
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
        line = (TargetDataLine)AudioSystem.getLine(info);
        line.open(format);
        line.start();
    }

    public void run() {
        if (!line.isRunning()) {
            System.out.println("starting line...");
            line.start();
        }
        while (true) {
            final int available = line.available();
            if (available > 0) {
                byte[] b = new byte[available];
                int count = line.read(b, 0, available);
                if (count == -1) {
                    return;
                }

                // the number of values also depends on the bits-per-sample - which is currently ignored.
                double[] values = new double[available];
                for (int i = 0; i < available; i++) {
                    if (line.getFormat().getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)) {
                        values[i] = b[i];
                    } else {
                        values[i] = (0xFF & b[i]);
                    }
                }
                bank.read(values);
            } else if (available < 0) {
                System.out.println("error? stream is not longer available.");
                return;
            } else {
                try {
                    sleep(10); // try to save some cpu time.
                } catch (InterruptedException e) { /* ignore */ }
            }
        }
    }

	private static AudioFormat getAudioFormat(final int sampleRate) {
		AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;

		int sampleSizeInBits = 8;
		int channels = 1;
		int frameSize = 1;
		int frameRate = sampleRate;
		boolean bigEndian = false;

		return new AudioFormat(encoding,
							   sampleRate,
							   sampleSizeInBits,
							   channels,
							   frameSize,
							   frameRate,
							   bigEndian);
	}
}